package fr.kapit.klovis.components
{
	
	
	import flash.events.MouseEvent;
	
	import mx.core.IFactory;
	
	import spark.components.Button;
	import spark.components.Group;
	import spark.components.HGroup;
	import spark.components.Label;
	import spark.components.TextInput;
	import spark.components.supportClasses.SkinnableComponent;
	import spark.layouts.HorizontalLayout;
	
	//--------------------------------------
	//  Skin states
	//--------------------------------------
	[SkinState("classic")]
	[SkinState("precise")]

	
	public class Rating extends SkinnableComponent
	{
		//--------------------------------------------------------------------------
		//
		//  Constants
		//
		//--------------------------------------------------------------------------
		public static const MAX_RATING:int = 5;
		
		
		//--------------------------------------------------------------------------
		//
		//  Constructor and Initialization
		//
		//--------------------------------------------------------------------------
		
		public function Rating()
		{
			super();
		}
		
		//--------------------------------------------------------------------------
		//
		//  Variables
		//
		//--------------------------------------------------------------------------
		private var _selectedRating:Button;
		
		private var _selectedPrecisionRating:Button;
		
		private var _precisionRatingGroup:HGroup;
		
		private var _isOpen:Boolean;
		
		
		//--------------------------------------------------------------------------
		//
		//  Properties
		//
		//--------------------------------------------------------------------------
		
		
		//----------------------------------
		//  label
		//---------------------------------- 
		
		[SkinPart(required="true")]
		
		/**
		 * A skin part that displays the rating value
		 */
		public var label:Label;
		
		//----------------------------------
		//  rateTextButton
		//---------------------------------- 
		
		[SkinPart(required="true")]
		
		/**
		 * A skin part that displays "rate me"
		 */
		public var rateTextButton:Button;
		
		
		//----------------------------------
		//  ratingGroup
		//---------------------------------- 
		
		[SkinPart(required="true")]
		
		/**
		 * A skin part that defines the group where rating components will be added
		 */
		public var ratingGroup:HGroup;
		
		//----------------------------------
		//  ratingButton
		//---------------------------------- 
		
		[SkinPart(required="true", type="spark.components.Button")]
		
		/**
		 * A dyamic skin part that defines a rating button
		 */
		public var ratingButton:IFactory;
		

		//----------------------------------
		//  preciseRatingGroup
		//---------------------------------- 
		
		[SkinPart(required="true", type="spark.components.HGroup")]	
		
		/**
		 * A skin part that defines where precision rating components will be added
		 */
		public var precisionRatingGroup:IFactory;
		
		
		//----------------------------------
		//  precisionRatingButton
		//---------------------------------- 
		
		[SkinPart(required="true", type="spark.components.Button")]
		
		/**
		 * A dyamic skin part that defines a precision rating button
		 */
		public var precisionRatingButton:IFactory;
		
		
		//----------------------------------
		//  dropDown
		//----------------------------------
		
		[SkinPart(required="true")]
		
		/**
		 * A static part where ratings will be added
		 */
		public var dropDown:Group;
		
		
		//----------------------------------
		//  value
		//---------------------------------- 
		private var _value:Number;
		
		public function get value():Number
		{
			return _value;
		}
		
		private function setValue(value:Number):void
		{
			_value = value;
			label.text = _value.toString();
		}
		
		
		
		//----------------------------------
		//  preciseRange
		//---------------------------------- 
		[Inspectable(minValue="0")]
		
		private var _precisionRange:uint;
		
		private var _bprecisionRangeChanged:Boolean
		
		public function set precisionRange(value:uint):void
		{
			if (value != _precisionRange)
			{
				_precisionRange = value;
				_bprecisionRangeChanged = true;
				invalidateProperties();
			}
		}
		
		public function get precisionRange():uint
		{
			return _precisionRange;
		}
		
		//--------------------------------------------------------------------------
		//
		//  Overriden SkinnableComponent methods
		//
		//--------------------------------------------------------------------------
		override protected function createChildren() : void
		{
			super.createChildren();
			
			createRatings();
			setValue(1);
		}
		
		override protected function partAdded(partName:String, instance:Object):void
		{
			super.partAdded(partName, instance);
			
			if (partName == "rateTextButton")
			{
				rateTextButton.addEventListener(MouseEvent.CLICK, openIcon_clickHandler);
			}
			
			if (partName == "ratingButton")
			{
				Button(instance).addEventListener(MouseEvent.ROLL_OVER, ratingButton_mouseOverHandler);
				Button(instance).addEventListener(MouseEvent.CLICK, ratingButton_clickHandler);
				
			}
			
			if (partName == "precisionRatingButton")
			{
				Button(instance).addEventListener(MouseEvent.ROLL_OVER, preciseButton_rollOverHandler);
				Button(instance).addEventListener(MouseEvent.CLICK, preciseButton_clickHandler);
			}
			
		}
		
		override protected function partRemoved(partName:String, instance:Object) : void
		{
			super.partAdded(partName, instance);
			
			if (partName == "rateTextButton")
			{
				rateTextButton.removeEventListener(MouseEvent.CLICK, openIcon_clickHandler);
			}
			
			if (partName == "ratingButton")
			{
				Button(instance).removeEventListener(MouseEvent.ROLL_OVER, ratingButton_mouseOverHandler);
				Button(instance).removeEventListener(MouseEvent.CLICK, ratingButton_clickHandler);
				
			}
			
			if (partName == "precisionRatingButton")
			{
				Button(instance).removeEventListener(MouseEvent.ROLL_OVER, preciseButton_rollOverHandler);
				Button(instance).removeEventListener(MouseEvent.CLICK, preciseButton_clickHandler);
			}
		}
		
		override protected function getCurrentSkinState():String
		{
			if (_isOpen)
				return "precise";
			else
				return "classic";
		}
		
		//--------------------------------------------------------------------------
		//
		//  Event Handlers
		//
		//--------------------------------------------------------------------------
		private function ratingButton_mouseOverHandler(e:MouseEvent):void
		{
			_selectedRating = e.target as Button;
			
			if (_precisionRange > 0)
			{
				_selectedRating = e.target as Button;
				displayPrecisionRatings();
			}
			
			computeValue();
		}
		
		private function ratingButton_clickHandler(e:MouseEvent):void
		{
			_selectedPrecisionRating = null;
			computeValue();
			closeDropDown();
		}
		
		private function openIcon_clickHandler(e:MouseEvent):void
		{
			openDropDown();
		}
		
		private function preciseButton_rollOverHandler(e:MouseEvent):void
		{
			_selectedPrecisionRating = e.target as Button;
			computeValue();
		}
		
		private function preciseButton_clickHandler(e:MouseEvent):void
		{
			closeDropDown();
		}
			
			
		//--------------------------------------------------------------------------
		//
		//  Private methods 
		//
		//--------------------------------------------------------------------------
		private function createRatings():void
		{
			var rating:Button;
			for (var i:int = 1; i <= MAX_RATING; i++)
			{
				rating = createDynamicPartInstance("ratingButton") as Button;
				rating.label = i.toString();
				ratingGroup.addElement(rating);
			}
		}
		
		private function computeValue():void
		{
			var value:String;
			
			if (_selectedRating)
				value = _selectedRating.label;
			
			if (_selectedPrecisionRating)
				value += _selectedPrecisionRating.label;
			
			setValue(parseFloat(value));
		}
		
		private function openDropDown():void
		{
			_isOpen = true;
			invalidateSkinState();
		}
		
		private function closeDropDown():void
		{
			_isOpen = false;
			invalidateSkinState();
		}
		
		private function displayPrecisionRatings():void
		{
			if (!_precisionRatingGroup)
			{
				initPrecisionRatingGroup();
				createPrecisionRatingButtons();
			}
			computePrecisionRatingGroupPosition();
		}
		
		private function initPrecisionRatingGroup():void
		{
			_precisionRatingGroup = createDynamicPartInstance("precisionRatingGroup") as HGroup;
			dropDown.addElement(_precisionRatingGroup);
		}
		
		private function createPrecisionRatingButtons():void
		{
			if (_precisionRange > 0)
			{
				var precisionRating:Button;
				var precision:Number = 1 / (_precisionRange+1);
				for (var i:int = 0; i < _precisionRange; i++)
				{
					precisionRating = createDynamicPartInstance("precisionRatingButton") as Button;
					precisionRating.label = (precision*(i+1)).toFixed(2).substring(1);
					_precisionRatingGroup.addElement(precisionRating);
				}
			}
			
		}
		
		private function computePrecisionRatingGroupPosition():void
		{
			HorizontalLayout(_precisionRatingGroup.layout).paddingLeft = _selectedRating.x;
			_precisionRatingGroup.validateNow();
		}

	}
}